/*
 * FnThread21.c
 * Created on Apr 29, 2004; 10:00 AM
 * by Kumar
 */
/*
** Copyright 2004 by Hellosoft Inc. All rights reserved. No part
** of this publication, or any software included with it, may be
** reproduced, stored in a retrieval system, or transmitted in
** any form or by any other means, including photocopying,
** electronic or mechanical recording or otherwise, without
** prior written permission of the copyright holder
**
** Hellosoft Confidential and Proprietary information
**
**-------------------------------------------------------------
**/

/************ System Header Files ***************/
#include <stdio.h>
#include <stdlib.h>

/************ Private Header Files **************/
#include "hs_types.h"
#include "HsTypes.h"
#include "PhyStruct.h"
#include "PmdGlobals.h"
#include "PhyConstants.h"
#include "tables.h"
#include "tx_start_header_gen.h"
#include "tx_functions.h"
#include "send_preamble.h"
#include "send_sfd.h"
#include "send_header.h"
#include "send_1mbps.h"
#include "send_2mbps.h"
#include "send_55mbps.h"
#include "send_11mbps.h"
#include "wlan_phy_mac.h"
#include "icrdefs_3500.h"
#include "iqdma_3500.h"
//#include "rf_api.h"
#include "thread_globals.h"
#include "threads_common.h"
#include "wlan_mac.h"

#define N_HEAD_SYMS					8 //INITIAL SYMBOLS before DMA start
#define HEADER_SYMBOLS              (PLCP_PREAMBLE_BITS + PLCP_SFD_BITS)
#define SHORT_HEADER_SYMBOLS        (PLCP_SHORT_PREAMBLE_BITS + PLCP_SFD_BITS)

volatile hs_int32_t tx_count = 0;

/** Precomputed Preamble+SFD samples **/
hs_int16_t HeaderSamplesI[HEADER_SYMBOLS*22] =
{
    #include "header_i.h"
};

hs_int16_t HeaderSamplesQ[HEADER_SYMBOLS*22] =
{
    #include "header_q.h"
};


hs_int16_t ShortHeaderSamplesI[SHORT_HEADER_SYMBOLS*22] =
{
    #include "short_header_i.h"
};

hs_int16_t ShortHeaderSamplesQ[SHORT_HEADER_SYMBOLS*22] =
{
    #include "short_header_q.h"
};

hs_uint8_t ucStateTable1Bit[128];
hs_uint8_t ucStateTable2Bit[128];
hs_uint8_t ucStateTable4Bit[128];
hs_int16_t asCckDqpsk11[1280];
hs_uint16_t usDQPSKNew[16];
hs_int16_t ssDBPSKTbl[48*2];
hs_int16_t ssDQPSKTbl[96*2];
hs_int16_t asCckDqpskSeq[512];
hs_uint16_t usCrc16Table_8bit[256];
hs_int16_t index11IQ[2*256];
hs_uint32_t crctab[WLAN_CRC_TAB];

hs_uint8_t crc_shared[4];
hs_uint8_t ucInputBit_shared_2_55[4*2];
hs_uint8_t ucInputBit_shared_11[4*2];
hs_uint32_t uiTempReg_shared[2*2];

hs_int32_t cck_index_11[12][256];
hs_uint8_t scrambytetable_11[2*256][16];

hs_int32_t tic3=0,tic4=0,tic7=0;

//hs_int16_t zeros[16]= {0};

struct HS_PhyTx11bStr  sPhyTx11bStr;

/** IQ Buffers **/
hs_int16_t DacOutI[GLOBAL_BUF_SIZE_TX+32];
hs_int16_t DacOutQ[GLOBAL_BUF_SIZE_TX+32];

//#define TX_RATE		(10)
//#define TX_LEN		(200)

static inline
void send_header_iq(
                        hs_int16_t * restrict srcI,
                        hs_int16_t * restrict dstI,
                        hs_int16_t * restrict srcQ,
                        hs_int16_t * restrict dstQ
                    )
{
    hs_int32_t i;

    /** Send 8 header symbols: 1 sub-buffer **/
    for(i=0; i<11; i++){
    	__sb_rcopy(&dstI[i*16], &srcI[i*16]);
    	__sb_rcopy(&dstQ[i*16], &srcQ[i*16]);
    }
}

void init_mapper_table()
{
	hs_int32_t i;
	hs_int32_t j;
	hs_int16_t ssTempReg;
	hs_int16_t ssPrevSymb;
	hs_uint8_t ucInputBit;
	hs_uint8_t ucBit;
	hs_uint8_t ucDiffSymbIndex;

	for(i=0; i<4; i++){
		for(j=0; j<256; j++){
			ssPrevSymb = i;
			ucInputBit = j;

			ucBit = ucInputBit & 0x3;
			ucDiffSymbIndex = usDQPSKNew[ssPrevSymb + (ucBit <<2)];
			cck_index_11[8+i][j] = ucDiffSymbIndex;

			ucBit =  ucInputBit & 0xFC;
	        ssTempReg = ucBit + ucDiffSymbIndex;
	        cck_index_11[i][j] = (hs_int32_t)&(asCckDqpsk11[index11IQ[ssTempReg]]);
	        cck_index_11[4+i][j] = (hs_int32_t)&(asCckDqpsk11[index11IQ[256+ssTempReg]]);
		}
	}
}

void init_scrambler_table()
{
	hs_int32_t i;
	hs_int32_t j;

	hs_uint8_t byte;
	hs_uint8_t scram_state;
	hs_uint8_t ucInputBit;

	for(i=0; i<16; i++){
		for(j=0; j<256; j++){
			byte = i;
			scram_state = j;
			ucInputBit   = ucStateTable4Bit[scram_state] ^ (byte);
		    scram_state >>= 4;
			scram_state |= (ucInputBit << 3);
			scrambytetable_11[256+j][i] = scram_state;
			scrambytetable_11[j][i] = ucInputBit;
		}
	}
}

void phy_tx_dac_init()
{
	struct HS_PhyTx11bStr *HS_PhyTx11bPtrTh1;

	HS_PhyTx11bPtrTh1 = &sPhyTx11bStr;

	/** Handle precomputed header part **/
	if(HS_PhyTx11bPtrTh1->preamble_type == LONG_PREAMBLE){
		send_header_iq(HeaderSamplesI, DacOutI, HeaderSamplesQ, DacOutQ);
      	}
	else{
		send_header_iq(ShortHeaderSamplesI, DacOutI, ShortHeaderSamplesQ, DacOutQ);
	}
}

void phy_tx_init()
{
	hs_int32_t i;

	struct HS_PhyTx11bStr *HS_PhyTx11bPtrTh1;

	HS_PhyTx11bPtrTh1 = &sPhyTx11bStr;

	/** Copy all Tx tables **/
	for(i=0; i<256*2; i++){
		index11IQ[i] = index11IQ_g[i];
	}

	for(i=0; i<128; i++){
		ucStateTable1Bit[i] = ucStateTable1Bit_g[i];
	    ucStateTable2Bit[i] = ucStateTable2Bit_g[i];
	    ucStateTable4Bit[i] = ucStateTable4Bit_g[i];
	}

	for(i=0; i<sizeof(usDQPSKNew_g)/sizeof(hs_uint16_t); i++){
		usDQPSKNew[i] = usDQPSKNew_g[i];
	}

	for(i=0; i<sizeof(ssDBPSKTbl_g)/sizeof(hs_int16_t); i++){
		ssDBPSKTbl[i] = ssDBPSKTbl_g[i];
	}
	for(i=0; i<sizeof(ssDQPSKTbl_g)/sizeof(hs_int16_t); i++){
		ssDQPSKTbl[i] = ssDQPSKTbl_g[i];
	}

	for(i=0; i<512; i++){
		asCckDqpskSeq[i] = asCckDqpskSeq_g[i];
	}
	for(i=0; i<1280; i++){
		asCckDqpsk11[i] = asCckDqpsk11_g[i];
	}

	for(i=0; i<256; i++){
		usCrc16Table_8bit[i] = usCrc16Table_8bit_g[i];
	}

	copy_crctable(crctab);
	init_scrambler_table();
	init_mapper_table();

	/* Check the D2A buffers' address alignment anyway */
	if( ((hs_int32_t)DacOutI & RF_SUBB_ALIGN) ||
	     ((hs_int32_t)DacOutQ & RF_SUBB_ALIGN))
	{
		fprintf(stderr,"RF buffers not aligned\n");
		fprintf(stderr,"%p %p %d %d\n", DacOutI, DacOutQ,
	              ((hs_int32_t)DacOutI & RF_SUBB_ALIGN),
	              ((hs_int32_t)DacOutQ & RF_SUBB_ALIGN));
	     exit (-28);
	}

	HS_PhyTx11bPtrTh1->psTxDtoAStartI = &DacOutI[0];
	HS_PhyTx11bPtrTh1->psTxDtoAStartQ = &DacOutQ[0];
	HS_PhyTx11bPtrTh1->psTxDtoAEndI = &DacOutI[GLOBAL_BUF_SIZE_TX];


	HS_PhyTx11bPtrTh1->crc_shared = crc_shared;
	HS_PhyTx11bPtrTh1->ucInputBit_shared_2_55 = ucInputBit_shared_2_55;
	HS_PhyTx11bPtrTh1->ucInputBit_shared_11 = ucInputBit_shared_11;
	HS_PhyTx11bPtrTh1->uiTempReg_shared = uiTempReg_shared;

	//HS_PhyTx11bPtrMain->preamble_type = SHORT_PREAMBLE;
	HS_PhyTx11bPtrTh1->preamble_type = LONG_PREAMBLE;

	//printf("address of tx count = %x\n", &tx_count);

	phy_tx_dac_init();
	tx_init_thread_flags();

}


void FnThread21(hs_int32_t target_speed, hs_int32_t length, hs_uint8_t *payload)
{
	hs_int32_t clock1;
	//static hs_int32_t cnt = 0;

	hs_int32_t terminate_myself = 0;
	//hs_int32_t  i;

	ePHYSTATES_TH  ePhyState;

	/* Tx Variables */
	struct HS_PhyTx11bStr  *HS_PhyTx11bPtrTh1;

	/** Core 1, PSD B **/
	hs_uint32_t core_base = ICR_ADDRESS_CORE(TX_CORE);
	hs_uint32_t d2a_base = ICR_ADDRESS_CORE_CHANNEL(TX_CORE, TX_PSD);

	hs_int16_t *psTxDtoAStartI;
	hs_int16_t *psTxDtoAStartQ;

	hs_uint8_t  *ucHeaderByte;
	hs_uint8_t  *psPayloadByte;
	hs_uint16_t usDateRate=0;
	hs_uint16_t usLength=0;

    //#if  No_frame_txtest
	/** Start the D2A IQDMA **/
	/* set I buffer start address */
	ICR_SET(d2a_base, REG_D2AISTR, (unsigned)DacOutI);
	/* set Q buffer start address */
	ICR_SET(d2a_base, REG_D2AQSTR, (unsigned)DacOutQ);

	//*((volatile unsigned*)0x80000FFC) = tx_count++; //__sb_cfsr(MACH_GIFR);

	/* set the buffer size and count and start the IQ DMA */
	ICR_SET(d2a_base,
			  REG_D2ACTL,
			  D2A_CTL_ENABLEI
			  |D2A_CTL_ENABLEQ
			  |(1 << 28)  //bit28=1)
			  |D2A_CTL_DECIMATION(0)
			  |D2A_CTL_BUFSIZE(SUB_BUF_SIZE_TX-4)
			  |D2A_CTL_BUFCOUNT(NSUBFS_TX-1));

	/** Enable D2A **/
	ICR_SET(core_base, TX_PSD_EN, 0x2);

	#if ENABLE_BASEBAND_LOOP
	Enable_timer(1,2);//enable PSD timer
	#endif

	HS_PhyTx11bPtrTh1 = &sPhyTx11bStr;
	HS_PhyTx11bPtrTh1->psTxDtoABufferI = DacOutI + N_HEAD_SYMS*22; //8 symbols
	HS_PhyTx11bPtrTh1->psTxDtoABufferQ = DacOutQ + N_HEAD_SYMS*22; //8 symbols
    HS_PhyTx11bPtrTh1->header_iq_offset = N_HEAD_SYMS*22; //8 symbols

	psTxDtoAStartI = HS_PhyTx11bPtrTh1->psTxDtoAStartI;
	psTxDtoAStartQ = HS_PhyTx11bPtrTh1->psTxDtoAStartQ;
	ucHeaderByte = HS_PhyTx11bPtrTh1->ucHeaderByte;
	psPayloadByte = payload;

	HS_PhyTx11bPtrTh1->tx_status_l = HS_INCOMPLETE;
	HS_PhyTx11bPtrTh1->usDateRate = target_speed;
	HS_PhyTx11bPtrTh1->usLength = length;
	HS_PhyTx11bPtrTh1->psPayloadByte = payload;

	//clock1 = __sb_cfsr(MACH_CYC);
    tic3 = __sb_cfsr(MACH_CYC);

	ePhyState = PHY_RX_DETECT_ENERGY_TH;

//	osFastPause(126720000);
	while(1)
	{
		switch(ePhyState)
		{
			/* ********************************* RX_STARTS ******************* */
			case PHY_RX_DETECT_ENERGY_TH:
			{
				//tic3 = __sb_cfsr(MACH_CYC);
				txstart_header_gen(
								HS_PhyTx11bPtrTh1,
								asCckDqpskSeq,
								ssDBPSKTbl,
								&ePhyState,
								ucStateTable1Bit,
								usCrc16Table_8bit
								);

				usDateRate = HS_PhyTx11bPtrTh1->usDateRate;
				usLength = HS_PhyTx11bPtrTh1->usLength;

				break;
			}/* case PHY_RX_DETECT_ENERGY */


		   /* ************************************************************* */
		   /* ********************************* TX_STARTS ******************* */

		   case PHY_STATE_TX_SEND_PREAMBLE_TH:
		   {
			   if(HS_PhyTx11bPtrTh1->preamble_type == LONG_PREAMBLE){
				   send_preamble(
								HS_PhyTx11bPtrTh1,
								ssDBPSKTbl,
								&ePhyState,
								psTxDtoAStartI,
								psTxDtoAStartQ,
								HeaderSamplesI,
								HeaderSamplesQ
						   );
			   }
			   else{
				   send_preamble(
								HS_PhyTx11bPtrTh1,
								ssDBPSKTbl,
								&ePhyState,
								psTxDtoAStartI,
								psTxDtoAStartQ,
								ShortHeaderSamplesI,
								ShortHeaderSamplesQ
						   );
			   }

			   break;
		   }/* case PHY_STATE_TX_SEND_PREAMBLE_TH */


		   case PHY_STATE_TX_SEND_SFD_TH:
		   {
			   if(HS_PhyTx11bPtrTh1->preamble_type == LONG_PREAMBLE){
				   send_sfd(
							HS_PhyTx11bPtrTh1,
							ssDBPSKTbl,
							&ePhyState,
							psTxDtoAStartI,
							psTxDtoAStartQ,
							HeaderSamplesI,
							HeaderSamplesQ
						 );
			   }
			   else{
				   send_sfd(
							HS_PhyTx11bPtrTh1,
							ssDBPSKTbl,
							&ePhyState,
							psTxDtoAStartI,
							psTxDtoAStartQ,
							ShortHeaderSamplesI,
							ShortHeaderSamplesQ
						 );
			   }

				break;
		   }/* case PHY_STATE_TX_SEND_SFD_TH */

		   case PHY_STATE_TX_SEND_HEADER_TH:
		   {
				 if(HS_PhyTx11bPtrTh1->preamble_type == SHORT_PREAMBLE){
					 send_header_2mbps(
							HS_PhyTx11bPtrTh1,
							ssDQPSKTbl,
							usDQPSKNew,
							&ePhyState,
							ucStateTable2Bit,
							psTxDtoAStartI,
							psTxDtoAStartQ
					);
				 }
				 else{

					send_header(
							HS_PhyTx11bPtrTh1,
							ssDBPSKTbl,
							&ePhyState,
							ucStateTable1Bit,
							psTxDtoAStartI,
							psTxDtoAStartQ,
							usDateRate,
							ucHeaderByte
						 );
				 }

				 #ifdef REDUCE_FREQUENCY_TX
				 /** Frequency Control **/
				 upscale_tpu_mhz(2);
				 *((volatile unsigned*)(0x8c000000+0x40)) &= 0xFFFC;
				 SPIN(50);
				 #endif

				 break;
		   }

		   case PHY_STATE_TX_SEND_PAYLOAD_1MBPS_TH:
		   {     //printf("enter 1M payload\n");
			   tic7 = __sb_cfsr(MACH_CYC);
			   send_1mbps(
						HS_PhyTx11bPtrTh1,
						ssDBPSKTbl,
						&ePhyState,
						ucStateTable1Bit,
						psTxDtoAStartI,
						psTxDtoAStartQ,
						crctab,
						usLength,
						psPayloadByte
					 );

				 break;
		   }/* case PHY_STATE_TX_SEND_PAYLOAD_1MBPS_TH */

		   case PHY_STATE_TX_SEND_PAYLOAD_2MBPS_TH:
		   {
			   //printf("The File %s Line %d\n",__FILE__,__LINE__);
			   tic7 = __sb_cfsr(MACH_CYC);
			   send_2mbps(
						HS_PhyTx11bPtrTh1,
						&ePhyState,
						ucStateTable2Bit,
						crctab,
						usLength,
						psPayloadByte
					 );

				 break;
		   }/* case PHY_STATE_TX_SEND_PAYLOAD_2MBPS_TH */

		   case PHY_STATE_TX_SEND_PAYLOAD_5DOT5MBPS_TH:
		   {
			    //printf("enter 5dot5M payload\n");
			     tic7 = __sb_cfsr(MACH_CYC);
				 send_55mbps(
					HS_PhyTx11bPtrTh1,
					&ePhyState,
					ucStateTable4Bit,
					crctab
				 );

				break;
		   }/* case PHY_STATE_TX_SEND_PAYLOAD_5DOT5MBPS_TH */

		   case PHY_STATE_TX_SEND_PAYLOAD_11MBPS_TH:
		   {
			     //printf("enter 11M payload\n");
			     tic7 = __sb_cfsr(MACH_CYC);
				 send_11mbps(
					HS_PhyTx11bPtrTh1,
					&ePhyState,
					ucStateTable4Bit,
					crctab
				);

				break;
		   }/* case PHY_STATE_TX_SEND_PAYLOAD_11MBPS_TH */

		   /* ********************************* TX_ENDS ******************* */

		   case PHY_STATE_SWITCH_OFF_TH:
		   {
			   //printf("The File %s Line %d\n",__FILE__,__LINE__);
			   //tic4=__sb_cfsr(MACH_CYC);
                while(HS_PhyTx11bPtrTh1->tx_status_l == HS_INCOMPLETE){
				  __sb_barrier();
				}
				SPIN(16); //required to handle L1->D2A latency

				tic4=__sb_cfsr(MACH_CYC);
				/** Stop the D2A **/
				ICR_SET(d2a_base, REG_D2ACTL, 0);

				#if ENABLE_BASEBAND_LOOP
				//Disable_timer(1,2);
				//reset_sub_buffer_interrupt();
				#endif

//				if (!mac_config_g.rf_disabled){
//					Lte_RfTransmitterOff(0);
//				}

				terminate_myself = 1;
				//tx_count = (__sb_cfsr(MACH_CYC) - clock1);

				break;
		   }/* case PHY_STATE_SWITCH_OFF_TH */


	  }/* switch ePhyState */

	  if(terminate_myself == 1)
	  {
		  //capture_all_iqdata_tx_samps(15840);//test
		  /*printf("Tx: rate = %d, len = %d, byte = %x %x\n", HS_PhyTx11bPtrTh1->usDateRate,
				  HS_PhyTx11bPtrTh1->usLength, HS_PhyTx11bPtrTh1->psPayloadByte[0],
				  HS_PhyTx11bPtrTh1->psPayloadByte[1]);*/
		  terminate_myself = 0;
		  break;
	  }
	  //printf("the estate is %d\n",ePhyState);
  }/* While */

}/* Function */

void
Layer1Transmit(hs_int32_t target_speed, hs_int32_t length, hs_uint8_t *payload)
{
	//static int cnt = 0;

	/** TX init starts **/
//	if (!mac_config_g.rf_disabled){
//		Lte_RfTransmitterOn(0);
//	}

	int e, f;

	tx_init_thread_flags();

	if(phy_rx_tx_dacinit_flag == 0){
		phy_tx_dac_init();
	}
	else{
		phy_rx_tx_dacinit_flag = 0;
	}

	tx_rx_mode_2 = TX_MODE;
	tx_rx_mode_3 = TX_MODE;

	#ifdef REDUCE_FREQUENCY_TX
	/** Frequency Control **/
	downscale_tpu_mhz(2);
	*((volatile unsigned*)(0x8c000000+0x40)) |= 0x0001;
	SPIN(50);
	#endif

//	printf("The File is %s, The Line is %d\n",__FILE__,__LINE__);


//	e = osFastClock();
//	printf("Time = %d\n",e);
	/** L1 TX **/
	FnThread21(target_speed, length, payload);


}



